#include "iic.h"
#include "gd32f30x.h"
#include "systick.h"

//  IIC 基础函数 
void IIC_DelayUs(uint8_t us)
{
    delay_1us(us);
}

void IIC_SdaModeOut()
{
    gpio_init(GPIOB, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, EE_SDA_PIN); // 推挽输出
}

void IIC_SdaModeIn()
{
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, EE_SDA_PIN); // 浮空输入
}

void IIC_SdaOutput_H()
{
    gpio_bit_write(GPIOB, EE_SDA_PIN, 1);
}

void IIC_SdaOutput_L()
{
    gpio_bit_write(GPIOB, EE_SDA_PIN, 0);
}

uint8_t IIC_SdaRead()
{
    return gpio_input_bit_get(GPIOB, EE_SDA_PIN); // 读取PB11引脚电平
}

void IIC_SclModeOut()
{
    gpio_init(GPIOB, GPIO_MODE_OUT_OD, GPIO_OSPEED_50MHZ, EE_SCL_PIN); // 推挽输出
}

void IIC_SclOutput_H()
{
    gpio_bit_write(GPIOB, EE_SCL_PIN, 1);
}

void IIC_SclOutput_L()
{
    gpio_bit_write(GPIOB, EE_SCL_PIN, 0);
}

//  IIC 基础函数 

void IIC_Init(void){
    rcu_periph_clock_enable(RCU_GPIOB);                                // 使能GPIOB时钟
    IIC_SclModeOut();
    IIC_SdaModeOut();
    IIC_SclOutput_H();
    IIC_SdaOutput_H();
}

void IIC_Start(void)
{
    IIC_SdaModeOut();
    IIC_SdaOutput_H();
    IIC_SclOutput_H();
    IIC_DelayUs(4); //>4.7us
    IIC_SdaOutput_L();
    IIC_DelayUs(4); //>4us
    IIC_SclOutput_L();
}

void IIC_Stop(void)
{
    IIC_SdaModeOut();
    IIC_SclOutput_L();
    IIC_SdaOutput_L();
    IIC_DelayUs(4); //>4us
    IIC_SclOutput_H();
    IIC_SdaOutput_H();
    IIC_DelayUs(4); //>4.7us
    // IIC_SdaOutput_L();
}

void IIC_Ack(void)
{
    IIC_SclOutput_L();
    IIC_SdaModeOut();
    IIC_SdaOutput_L();
    IIC_DelayUs(1);
    IIC_SclOutput_H();
    IIC_DelayUs(2); //>4us
    IIC_SclOutput_L();
}

void IIC_NoAck(void)
{
    IIC_SclOutput_L();
    IIC_SdaModeOut();
    IIC_SdaOutput_H();
    IIC_DelayUs(1);
    IIC_SclOutput_H();
    IIC_DelayUs(1); //>4us
    IIC_SclOutput_L();
}

uint8_t IIC_WaitAck(void)
{
    uint8_t u8ErrCnt = 0;
    IIC_SdaModeIn(); // 输入状态
    IIC_SdaOutput_H();
		IIC_DelayUs(1);
    IIC_SclOutput_H();
		IIC_DelayUs(1);
    while (IIC_SdaRead() == 1)
    {
        u8ErrCnt++;
        if (u8ErrCnt > 250)
        {
            IIC_Stop(); // 发送停止信号
            return 1;
        }
    }
    IIC_SclOutput_L();
    return 0;
}

void IIC_WriteByte(uint8_t u8Data)
{
    uint8_t i;
    uint8_t u8Temp;
    IIC_SdaModeOut();
    IIC_SclOutput_L();
    for (i = 0; i < 8; i++)
    {
#ifdef IIC_LSB // 低位在前
        u8Temp = ((u8Data << (7 - i)) & 0x80);
        (u8Temp == 0x80) ? (IIC_SdaOutput_H()) : (IIC_SdaOutput_L());
#else // 高位在前
        u8Temp = ((u8Data >> (7 - i)) & 0x01);
        (u8Temp == 0x01) ? (IIC_SdaOutput_H()) : (IIC_SdaOutput_L());
#endif
        IIC_DelayUs(2);
        IIC_SclOutput_H(); // 时钟保持高电平
        IIC_DelayUs(2);
        IIC_SclOutput_L(); // 时钟拉低，才允许SDA变化
    }
    IIC_DelayUs(2);
}

uint8_t IIC_ReadByte(void)
{
    uint8_t i;
    uint8_t bit = 0;
    uint8_t data = 0;
    IIC_SdaModeIn(); // 输入状态
    for (i = 0; i < 8; i++)
    {
        IIC_SclOutput_L();
        IIC_DelayUs(1);
        IIC_SclOutput_H();
        bit = IIC_SdaRead(); // 读出1位
#ifdef IIC_LSB               // 低位在前
        data |= (bit << i);
#else // 高位在前
        data = (data << 1) | bit;
#endif
        IIC_DelayUs(1);
    }
    return data;
}